home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / m2 / cat3src / cat / edittool.i < prev    next >
Text File  |  1997-10-26  |  65KB  |  1,966 lines

  1. IMPLEMENTATION MODULE EditTools;
  2. (*$S-*)
  3.  
  4. FROM SYSTEM     IMPORT  ADDRESS, ADR, TSIZE, CADR, LOC, LONGWORD, CALLSYS;
  5.  
  6. (* Megamax-Lib *)
  7.  
  8. FROM Storage    IMPORT ALLOCATE, DEALLOCATE;
  9.  
  10. FROM GrafBase   IMPORT Rectangle, LongRect, Point;
  11.  
  12. IMPORT Strings, FileNames, BinOps, Block, StrConv, MOSGlobals, Keyboard, SysVars2;
  13.  
  14. FROM Keyboard  IMPORT SpecialCode;
  15.  
  16. (* MagicLib *)
  17. IMPORT MagicAES, MagicDOS, MagicXBIOS, MagicSys, mtAlerts, mtAppl, mtDials, mtUtils;
  18.  
  19. (* CAT Module *)
  20. FROM Void       IMPORT v;
  21. IMPORT CatGlobal;
  22. IMPORT WdwManager;
  23.  
  24. (* Editor  *)
  25. FROM EditTypes  IMPORT EDITPTR, aLinePtr, aLineDesc, textPtr, aMark, deskSize, pixOff, undoType, TrennSet, 
  26.                        searchDir, CharSet, SuchModus, SuchFlags, theDrawLine, aBufferPtr, CAT, maxBlocks;
  27.  
  28. FROM EditGlobals        IMPORT  InqTextextend,  SetDocument, GetTextWidth,
  29.                                 ClipWork, MouseIsOn, CursorIsOn, HideCursor, ShowCursor, SaveMouse, RestoreMouse,
  30.                                 MouseCursor, ShowMouse, HideMouse, RowToIndex;
  31.                                 
  32. FROM EditDraw           IMPORT scrollRegion, drawLine, CenterCurrline, redrawLines, ShowBlockMark, 
  33.                                MarkArea;
  34.  
  35. IMPORT EditTypes;
  36. IMPORT EditGlobals;
  37. IMPORT EditBase;
  38. IMPORT EditDraw;
  39. IMPORT Find2;
  40. IMPORT Varnames;
  41. IMPORT ConfVars;
  42.  
  43. CONST    TAB     = 11C;
  44.  
  45. TYPE
  46.      bigBufferPtr = POINTER TO ARRAY [0..$FFFFFFFF] OF CHAR;
  47.                        
  48. TYPE undoBufferType = RECORD
  49.                         whatToUndo   : undoType;
  50.                         buffer       : bigBufferPtr;
  51.                         bufSize      : LONGCARD;
  52.                         oldStart,
  53.                         oldEnd,
  54.                         newStart,
  55.                         newEnd       : aMark;
  56.                         undoLine     : aLineDesc;
  57.                         lines        : LONGINT;
  58.                         atEndOfText  : BOOLEAN;
  59.                         wdw          : INTEGER;
  60.                       END;
  61.                         
  62. VAR 
  63.     undoBuffer  : undoBufferType;
  64.     undoList    : aLinePtr;
  65.     saveLinePtr : aLinePtr;
  66.     saveLineNr  : LONGINT;
  67.  
  68.     system,
  69.     lastInfoLine : LONGCARD;
  70.     lastInfoWin  : INTEGER;
  71.     lastLine     : LONGINT;
  72.     lastTotal    : LONGINT;
  73.     lastRow      : INTEGER;
  74.     lastInsert   : BOOLEAN;
  75.     lastIndent   : BOOLEAN;
  76.     
  77.     (* Variablen fr Suchen und Ersetzen mit Wildcards *)
  78.  
  79.     (* In diesen Arrays wird fr jedes Wildcardzeichen gespeichert,
  80.      * das wievielte Wildcardzeichen es insgesamt ist!
  81.      *)
  82.     allWildNumbers  : ARRAY [0..9] OF INTEGER;
  83.     oneWildNumbers  : ARRAY [0..9] OF INTEGER;
  84.  
  85.     (* Das compilerte Suchpattern *)
  86.     pPatt : Find2.tpPattern;
  87.     ptrPatt : Find2.tpPat;
  88.     
  89.     (* Suchmuster initialisiert: *)
  90.     searchInited: BOOLEAN;
  91.     
  92.  
  93. PROCEDURE SystemTimer();
  94. BEGIN
  95.   system := SysVars2._hz_200;
  96. END SystemTimer;
  97.  
  98. PROCEDURE SetInfoLine (ed : EDITPTR);
  99.   VAR adr : RECORD a,b : ADDRESS; END;
  100.       text: textPtr;
  101. BEGIN
  102.   IF ~ed^.showInfo THEN RETURN END;
  103.   MagicXBIOS.Supexec (ADDRESS(SystemTimer));
  104.   IF ((system < 100) OR (system - lastInfoLine > 100))
  105.   &  ((lastInfoWin # ed^.wdw)  OR 
  106.       (ed^.currLineNr # lastLine) OR 
  107.       (ed^.currRow # lastRow) OR 
  108.       (ed^.autoIndent # lastIndent) OR 
  109.       (ed^.insertMode # lastInsert) OR 
  110.       (ed^.totalLineNr # lastTotal))
  111.   THEN
  112.     lastInfoLine := system;
  113.     WITH ed^ DO 
  114.       lastLine := currLineNr;
  115.       lastTotal := totalLineNr;
  116.       lastRow := currRow;
  117.       lastIndent := autoIndent;
  118.       lastInsert := insertMode;
  119.       lastInfoWin := wdw;
  120.       IF ~readOnly OR listMode
  121.       THEN
  122.         Strings.Assign (' Zeile: ',WindowInfo, v.bool);
  123.         Strings.Append (StrConv.IntToStr (currLineNr+1, 0), WindowInfo, v.bool);
  124.         Strings.Append ('/', WindowInfo, v.bool);
  125.         Strings.Append (StrConv.IntToStr (totalLineNr, 0), WindowInfo, v.bool);
  126.         Strings.Append ('   Spalte: ', WindowInfo, v.bool);
  127.         IF realTabs
  128.         THEN
  129.           v.bool := EditBase.GetLineAdr (ed, currLineNr, text, v.int);
  130.           Strings.Append (StrConv.IntToStr (RowToIndex(text^, currRow, tabSize), 0), WindowInfo, v.bool);
  131.         ELSE
  132.           Strings.Append (StrConv.IntToStr (currRow, 0), WindowInfo, v.bool);
  133.         END;
  134.         IF insertMode THEN 
  135.           Strings.Append ('  Einfgen', WindowInfo, v.bool);
  136.         ELSE
  137.           Strings.Append ('  šberschreiben', WindowInfo, v.bool);
  138.         END;
  139.         IF autoIndent 
  140.         THEN
  141.           Strings.Append ('/Einrcken', WindowInfo, v.bool);
  142.         END;
  143.       END;
  144.       WdwManager.SetWdwInfoline (wdw, WindowInfo);
  145.     END;
  146.   END;
  147. END SetInfoLine;
  148.  
  149. PROCEDURE SetEditTitle (ed : EDITPTR);
  150.   VAR adr : RECORD a,b : ADDRESS; END;
  151. BEGIN
  152.   WITH ed^ DO 
  153.     IF ~readOnly
  154.     THEN
  155.       ConfVars.GetConfDefBool (cSetAppName, v.bool, TRUE);
  156.       IF CatGlobal.multiTask & v.bool
  157.       THEN
  158.         (*$? CAT: 
  159.         Strings.Assign (' [CAT] ',WindowTitle, v.bool);
  160.         *)
  161.         (*$? NOT CAT: 
  162.         Strings.Assign (' [Fred] ',WindowTitle, v.bool);
  163.         *)
  164.       ELSE
  165.         WindowTitle := '';
  166.       END;
  167.       (* Changed anzeigen mit '*' vor Dateinamen *)
  168.       IF changed THEN Strings.Append ('*',WindowTitle, v.bool) END;
  169.       IF fileName.length # 0
  170.       THEN
  171.         Strings.Append (fileName.text^, WindowTitle, v.bool);
  172.       ELSE
  173.         Strings.Append ('namenlos.txt', WindowTitle, v.bool);
  174.       END;
  175.       Strings.Append (' ', WindowTitle, v.bool); 
  176.     END;
  177.     WdwManager.SetWdwTitle (wdw, WindowTitle);
  178.   END;
  179. END SetEditTitle;
  180.  
  181. PROCEDURE ShowFileChanged (ed : EDITPTR);
  182. BEGIN
  183.   IF ~ed^.changed & ~ed^.readOnly THEN
  184.     ed^.changed := TRUE & ~ed^.readOnly;
  185.     SetEditTitle(ed);
  186.   END;
  187. END ShowFileChanged;
  188.  
  189. PROCEDURE UpdateCurrLine (VAR ed : EDITPTR; line : LONGINT);
  190. BEGIN
  191.   WITH ed^ DO
  192.     saveLineNr := -1;
  193.     currLineNr := BinOps.HigherLInt (0, line);
  194.     currLineNr := BinOps.LowerLInt (totalLineNr-1, line);
  195.     v.bool := EditBase.GetLineLength (ed, currLineNr, editLen);
  196.     IF editLen >= editLine.length 
  197.     THEN
  198.       DEALLOCATE (editLine.text, 0);
  199.       editLine.length := ((editLen + 16) DIV 16) * 16;
  200.       ALLOCATE (editLine.text, editLine.length);
  201.       IF editLine.text = NIL THEN 
  202.         (* Kein Speicher frei, kompaktieren *)
  203.         v.bool := EditBase.CompactBuffer (ed);
  204.         ALLOCATE (editLine.text, editLine.length);
  205.         IF editLine.text = NIL THEN HALT END;
  206.       END;
  207.     END;
  208.     Block.Clear (editLine.text, editLine.length);
  209.     EditBase.GetCurrLine (ed, editLine.text^, editLen);
  210.     editChanged := FALSE;
  211.   END;
  212. END UpdateCurrLine;
  213.  
  214. PROCEDURE SetCurrLine (VAR ed : EDITPTR; line : LONGINT);
  215. BEGIN
  216.   WITH ed^ DO
  217.     IF line = currLineNr THEN RETURN END;
  218.     line := BinOps.HigherLInt (0, line);
  219.     line := BinOps.LowerLInt (totalLineNr-1, line);
  220.     IF editChanged 
  221.     THEN
  222.       (*
  223.       IF editLen # INTEGER(LENGTH (editLine.text^)) THEN HALT END;
  224.       *)
  225.       v.bool := EditBase.PutCurrLine (ed);
  226.       editChanged := FALSE;
  227.     END;
  228.     UpdateCurrLine (ed, line);
  229.   END;
  230. END SetCurrLine;
  231.  
  232. PROCEDURE SetStartLine (VAR ed : EDITPTR; line : LONGINT; docUpdate : BOOLEAN);
  233. BEGIN
  234.   WITH ed^ DO 
  235.     StartLine := BinOps.HigherLInt (0, line);
  236.     StartLine := BinOps.LowerLInt (totalLineNr-1, line);
  237.     StartLine := line;
  238.     IF docUpdate THEN SetDocument (ed) END;
  239.   END;
  240. END SetStartLine;
  241.  
  242.         (* Abfrage-Funktionen           *)
  243.  
  244. PROCEDURE getCharPos (VAR ed : EDITPTR; line : LONGINT; row : INTEGER; VAR x, y : INTEGER);
  245. VAR 
  246.       saveLine  : LONGINT;
  247.       extend    : ARRAY [0..3] OF Point;
  248.       saveCh    : CHAR;
  249.       charAdr   : POINTER TO CHAR;
  250.       restoreLine : BOOLEAN;
  251.       text        : textPtr;
  252.       len         : INTEGER;
  253. BEGIN
  254.   WITH ed^ DO 
  255.     IF line # currLineNr
  256.     THEN 
  257.       restoreLine := TRUE;
  258.       saveLine := currLineNr;
  259.       SetCurrLine (ed, line);
  260.     ELSE
  261.       restoreLine := FALSE;
  262.     END;
  263.     y := editWork.y + SHORT(currLineNr - StartLine) * charHeight;
  264.     IF row < 0 THEN x := editWork.x; RETURN END;
  265.     IF ~monoSpaced OR realTabs OR parseEffects
  266.     THEN
  267.       (* So geht's schneller: *)
  268.       v.bool := EditBase.GetLineAdr (ed, line, text, len);
  269. (* Neu geschrieben fr Effekte 
  270.       IF row > len THEN row := len END;
  271.       charAdr := ADR (text^[row]);
  272.       saveCh := charAdr^;
  273.       (* String terminieren *)
  274.       charAdr^ := 0C;
  275.       (* Cursorposition bestimmen *)
  276.       IF realTabs
  277.       THEN
  278.         CatGlobal.ConvertTabs (text^, theDrawLine, tabSize);
  279.         text := ADR(theDrawLine);
  280.       END;
  281.       InqTextextend (ed, text^, extend, TRUE);
  282.       (* Žnderung wieder rckg„ngig machen *)
  283.       charAdr^ := saveCh;
  284. *)
  285.       IF ~v.bool
  286.       THEN
  287.         x := 0;
  288.         y := 0;
  289.       ELSE
  290.         charAdr := ADR (text^[len]);
  291.         saveCh := charAdr^;
  292.         (* String terminieren *)
  293.         charAdr^ := 0C;
  294.         (* Cursorposition bestimmen *)
  295.         IF realTabs
  296.         THEN
  297.           CatGlobal.ConvertTabs (text^, theDrawLine, tabSize);
  298.           row := RowToIndex (text^, row, tabSize);
  299.           text := ADR(theDrawLine);
  300.           len := LENGTH (theDrawLine);
  301.         END;
  302.         IF row > len THEN row := len END;
  303.         (* Jetzt Breite bestimmen *)
  304.         GetTextWidth (ed, text^, row, extend);
  305.         charAdr^ := saveCh;
  306.         (*----*)
  307.         x := editWork.x + extend[1].x - extend[0].x + pixOff - leftOffset;
  308.       END;
  309.     ELSE
  310.       x:= editWork.x + pixOff - leftOffset + row * charWidth;
  311.     END;
  312.     IF restoreLine
  313.     THEN 
  314.       SetCurrLine (ed, saveLine);
  315.     END;
  316.   END (* WITH ed^ DO *)
  317. END getCharPos;
  318.  
  319. (* Neues Konzept fr UNDO:
  320.  * Es werden pro Datei 64 Operationen gemerkt. Eine Operation ist dabei 
  321.  * folgendes:
  322.  * 
  323.  * - Einfgen eines Wortes (= alle Zeichen bis zu einem Space oder Befehl)
  324.  * - Einfgen eines oder mehrerer Zeilenumbrche
  325.  * - Einfgen, Ersetzen oder L”schen eines Blocks (oder Files)
  326.  *
  327.  * Implementation: 
  328.  * Es wird ein Array von Undobuffern implementiert, in dem die Operationen
  329.  * alle festgehalten werden. Dieses Array stellt einen Ring dar, wobei ein
  330.  * globaler Index festh„lt, welches Element das erste im Ring ist.
  331.  * In jedem Undobuffer wird festgehalten, die wievielte Operation dies
  332.  * im Ring ist, sowie alle ben”tigten Daten zur Rckg„ngigmachung der
  333.  * Aktion. Dazu wird folgendes festgehalten:
  334.  * Die Anzahl der Zeichen, die eingefgt oder gel”scht wurden.
  335.  * Die Zeichen, die eingefgt oder gel”scht wurden (in einem Buffer)
  336.  * Die aktuelle Cursorposition
  337.  * Die Position der Blockmarken vor und nach der Operation
  338.  * 
  339.  *
  340.  * Da diese Operationen teilweise sehr speicherintensiv sein k”nnen,
  341.  * ist es notwendig, einen Teil der Implementation in EditBase vorzunehmen, 
  342.  * damit bei einer Speicherknappheit die „ltesten Undooperationen 
  343.  * auch gel”scht werden k”nnen.
  344.  * Da die Implementation pro Datei erfolgen soll, ist es notwendig, den 
  345.  * Undobuffer in den Typ EDITOR mit aufzunehmen. Dadurch w„chst der Platz-
  346.  * bedarf der Editor-Struktur nochmal deutlich an.
  347.  *)
  348.  
  349. (* (* neue Implementation, erstmal als Kommentar. *)
  350. CONST   maxUndo = 32;
  351.  
  352. TYPE undoBufferType = RECORD
  353.                         operationNr  : LONGCARD;
  354.                         whatToUndo   : undoType;
  355.                         buffer       : bigBufferPtr;
  356.                         bufSize      : LONGCARD;
  357.                         oldStart,
  358.                         oldEnd,
  359.                         newStart,
  360.                         newEnd       : aMark;
  361.                         wdw          : INTEGER;
  362.                       END;
  363.  
  364. TYPE undoArrayType = ARRAY [0..maxUndo-1] OF undoBufferType;
  365.  
  366. TYPE undoDescriptor = RECORD
  367.                         undoIndex   : INTEGER;
  368.                         undoMax     : INTEGER;
  369.                         undoBuffers : undoArrayType;
  370.                         undoDone    : BOOLEAN;
  371.                       END;
  372.  
  373.  
  374.  
  375. *)
  376.  
  377. PROCEDURE ClearUndoBuffer (); FORWARD;
  378.  
  379. PROCEDURE SaveLine(VAR l : aLinePtr; lNr : LONGINT);
  380. BEGIN
  381.   IF lNr # saveLineNr
  382.   THEN
  383.     IF saveLinePtr^.zeile.text # NIL THEN DEALLOCATE (saveLinePtr^.zeile.text, 0) END;
  384.     IF l^.zeile.length < 0 THEN HALT END;
  385.     ALLOCATE (saveLinePtr^.zeile.text, l^.zeile.length);
  386.     IF saveLinePtr^.zeile.text = NIL
  387.     THEN
  388.       saveLineNr := -1;
  389.       saveLinePtr^.zeile.length := 0;
  390.     ELSE
  391.       saveLineNr := lNr;
  392.       saveLinePtr^.zeile.length := l^.zeile.length;
  393.       Strings.Assign (l^.zeile.text^, saveLinePtr^.zeile.text^, v.bool);
  394.     END;
  395.     ClearUndoBuffer();
  396.   END;
  397. END SaveLine;
  398.  
  399. PROCEDURE PutInUndoList (line : aLinePtr);
  400. BEGIN
  401.   (* Zeile in Undopuffer h„ngen *)
  402.   line^.next := undoList;
  403.   line^.prev := NIL;
  404.   undoList := line;
  405. END PutInUndoList;
  406.  
  407. PROCEDURE DeleteLine (VAR ed : EDITPTR; redraw : BOOLEAN);
  408.   VAR line : aLinePtr;
  409.       cursOn : BOOLEAN;
  410.       i      : INTEGER;
  411.       scroll : BOOLEAN;
  412. BEGIN
  413.   WITH ed^ DO
  414.     HideMouse();
  415.     HideCursor (ed);
  416.     ShowFileChanged (ed);
  417.     scroll := TRUE;
  418.     IF currLineNr = totalLineNr - 1 THEN
  419.       (* Letzte Zeile: Nur Inhalt l”schen! *)
  420.       editLine.text^ := 15C+12C+0C;
  421.       editLen := 2;
  422.       editChanged := TRUE;
  423.       v.bool := EditBase.PutCurrLine (ed);
  424.       EditDraw.redrawLine (ed, FALSE, TRUE);
  425.     ELSE
  426.       editChanged := FALSE; 
  427.       IF ~EditBase.DeleteLine (ed, currLineNr) THEN RETURN END;
  428.       UpdateCurrLine (ed, currLineNr);
  429.       IF redraw THEN
  430.         (* Bildschirm neu aufbauen *)
  431.         IF ((currLineNr - StartLine)+1 < LONG (windLines))
  432.         THEN
  433.           scrollRegion (ed, SHORT(currLineNr - StartLine), windLines, -1);
  434.           (* drawLine (ed, windLines-1); *)
  435.           (* drawLine (ed, windLines); *)
  436.         ELSE
  437.           (* nur unterste Zeile neu zeichnen *)
  438.           drawLine (ed, windLines - 1);
  439.         END;
  440.       END; (* IF redraw *)
  441.     END;
  442.     SetDocument (ed);
  443.     ShowCursor (ed);
  444.     ShowMouse(FALSE);
  445.   END; (* WITH ed^ *)
  446. END DeleteLine;
  447.  
  448. PROCEDURE freeUndoBuffer();
  449. BEGIN
  450.   WITH undoBuffer DO 
  451.     DEALLOCATE (buffer, 0);
  452.     bufSize := 0;
  453.     IF undoLine.text # NIL THEN DEALLOCATE (undoLine.text, 0) END;
  454.     undoLine.text := NIL;
  455.     undoLine.text := NIL;
  456.     buffer := NIL;
  457.     lines := 0;
  458.   END;
  459. END freeUndoBuffer;
  460.  
  461. PROCEDURE ClearUndoBuffer();
  462. BEGIN
  463.   IF undoBuffer.whatToUndo # nothingToDo 
  464.   THEN 
  465.     freeUndoBuffer();
  466.     undoBuffer.whatToUndo := nothingToDo;
  467.   END;
  468. END ClearUndoBuffer;
  469.  
  470. PROCEDURE CheckAndFreeUndo(wdw: INTEGER);
  471. BEGIN
  472.  IF wdw = undoBuffer.wdw 
  473.  THEN
  474.    ClearUndoBuffer();
  475.  END;
  476. END CheckAndFreeUndo;
  477.  
  478. PROCEDURE FreeUndoBuffer();
  479. BEGIN
  480.   IF saveLinePtr^.zeile.text # NIL THEN DEALLOCATE (saveLinePtr^.zeile.text, 0) END;
  481.   saveLineNr := -1;
  482.   saveLinePtr^.zeile.length := 0;
  483.   ClearUndoBuffer();
  484. END FreeUndoBuffer;
  485.  
  486. PROCEDURE Undo (VAR ed : EDITPTR);
  487.   VAR line : aLinePtr;
  488.       tmp  : aLineDesc;
  489.       cursOn : BOOLEAN;
  490.       m1, m2 : aMark;
  491.       secondBuff : bigBufferPtr;
  492.       secondSize : LONGCARD;
  493.       blEnd  : LONGINT;
  494.   
  495. BEGIN
  496.   HideCursor (ed);
  497.   WITH ed^ DO
  498.     IF editChanged
  499.     THEN
  500.       editChanged := FALSE;
  501.       UpdateCurrLine (ed, currLineNr);
  502.     ELSE
  503.       IF ed^.wdw # undoBuffer.wdw THEN 
  504.         CatGlobal.Bing(0); 
  505.         ShowCursor (ed);
  506.         RETURN 
  507.       END;
  508.       WITH undoBuffer DO 
  509.         CASE whatToUndo OF
  510.           blockToChar,
  511.           blockCut    : (* Es wird der gesicherte Block an der alten Stelle wieder eingefgt. 
  512.                          * Da die kompletten Start- und Endzeilen gesichert wurden, muž die
  513.                          * aktuelle Zeile nur gesichert werden und dann gel”scht und dann der 
  514.                          * alte Block eingefgt werden
  515.                          *)
  516.                         (* Alte Position wieder herstellen *)
  517.                         SetCurrLine (ed, oldStart.line);
  518.                         (* Erstmal aktuelle Zeile in Undobuffer sichern *)
  519.                         ALLOCATE (undoLine.text, editLine.length);
  520.                         IF undoLine.text = NIL
  521.                         THEN
  522.                           whatToUndo := nothingToDo;
  523.                         ELSE
  524.                           undoLine.length := editLine.length;
  525.                           Strings.Assign (editLine.text^, undoLine.text^, v.bool);
  526.                           newStart.line := currLineNr;
  527.                           newEnd.line   := currLineNr;
  528.                           lines := 1;
  529.                         END;
  530.                         (* Aktuelle Zeile in Buffer schreiben (Datenkonsistenz) *)
  531.                         v.bool := EditBase.PutCurrLine (ed);
  532.                         ed^.currRow := oldStart.row;
  533.                         (* Aktuelle und n„chste Zeile l”schen *)
  534.                         IF ~atEndOfText
  535.                         THEN 
  536.                           IF (currLineNr < totalLineNr - 1)  THEN 
  537.                             v.bool := EditBase.DeleteLine (ed, currLineNr+1);
  538.                           END;
  539.                         END;
  540.                         v.bool := EditBase.DeleteLine (ed, currLineNr);
  541.                         (* Undobuffer jetzt einkopieren *)
  542.                         ed^.currLineNr := oldStart.line;
  543.                         ed^.currRow := 0;
  544.                         ed^.block := TRUE;
  545.                         v.bool := EditBase.InsertBuffer (ed, buffer, bufSize, TRUE);
  546.                         ed^.currRow := oldStart.row;
  547.                         buffer := NIL;
  548.                         bufSize := 0;
  549.                         (* Jetzt neuen Undotyp setzen *)
  550.                         IF (whatToUndo = blockCut) OR (whatToUndo = blockToChar)   (* kann vorher ver„ndert worden sein *)
  551.                         THEN
  552.                           whatToUndo := cutUndo
  553.                         END;
  554.                         (* Jetzt Blockmarken wiederherstellen *)
  555.                         blocks[0].blockStart := oldStart;
  556.                         blocks[0].blockEnd := oldEnd;
  557.                         block := TRUE;
  558.                         |
  559.           blockPaste  : (* Vorgehensweise: Aktuellen Block sichern und dann ausschneiden,
  560.                          * dann letzten Block wieder einfgen. Blockmarken umsetzen.
  561.                          *)
  562.                         WITH ed^ DO
  563.                           IF (blocks[0].blockEnd.line < 0) OR (blocks[0].blockStart.line < 0) THEN 
  564.                             ShowCursor (ed);
  565.                             RETURN 
  566.                           END;
  567.                           newStart := blocks[0].blockStart;
  568.                           newEnd   := blocks[0].blockEnd;
  569.                           (* gesamten Block duplizieren *)
  570.                           IF ~EditBase.CopyToBuff (ed, blocks[0].blockStart.line, blocks[0].blockEnd.line+1, secondBuff, secondSize)
  571.                           THEN
  572.                             whatToUndo := nothingToDo;
  573.                           END;
  574.                           (* Jetzt diesen Block ausschneiden! *)
  575.                           IF blocks[0].blockEnd.line >= totalLineNr-1
  576.                           THEN
  577.                             blEnd := blocks[0].blockEnd.line
  578.                           ELSE
  579.                             blEnd := blocks[0].blockEnd.line + 1;
  580.                           END;
  581.                           v.bool := EditBase.DeleteSomeLines (ed, blocks[0].blockStart.line, blEnd);
  582.                           (* Und jetzt den alten wieder einfgen *)
  583.                           SetCurrLine (ed, oldStart.line);
  584.                           currRow := oldStart.row;
  585.                           (* Undobuffer jetzt einkopieren *)
  586.                           v.bool := EditBase.InsertBuffer (ed, buffer, bufSize, TRUE);
  587.                           currRow := oldStart.row;
  588.                           IF whatToUndo = blockPaste THEN
  589.                             buffer := secondBuff;
  590.                             bufSize := secondSize;
  591.                           ELSE 
  592.                             buffer := NIL;
  593.                             bufSize := 0;
  594.                           END;
  595.                           (* Blockmarken setzen *)
  596.                           blocks[0].blockStart := oldStart;
  597.                           blocks[0].blockEnd   := oldEnd;
  598.                           (* Jetzt noch Blockmarken swappen, falls blockPaste *)
  599.                           IF (whatToUndo = blockPaste)
  600.                           THEN
  601.                             m1 := newStart;
  602.                             newStart := oldStart;
  603.                             oldStart := m1;
  604.                             m1 := newEnd;
  605.                             newEnd := oldEnd;
  606.                             oldEnd := m1;
  607.                           END;
  608.                           (* SaveOp fr n„chstes Undo setzen *)
  609.                           block := TRUE;
  610.                         END; |
  611.                         |
  612.           cutUndo,
  613.           normalPaste : (* Blockbereich komplett l”schen und einfach alte Zeile restaurieren *)
  614.                         (* gesamten Block duplizieren *)
  615.                         SetCurrLine (ed, oldStart.line);
  616.                         IF oldEnd.line >= totalLineNr-1
  617.                         THEN
  618.                           blEnd := oldEnd.line;
  619.                         ELSE
  620.                           blEnd := oldEnd.line + 1;
  621.                         END;
  622.                         DEALLOCATE (buffer,0);
  623.                         buffer := NIL;
  624.                         bufSize := 0;
  625.                         IF ~EditBase.CopyToBuff (ed, oldStart.line, blEnd, buffer, bufSize)
  626.                         THEN
  627.                           whatToUndo := nothingToDo;
  628.                           freeUndoBuffer();
  629.                           ShowCursor (ed);
  630.                           RETURN
  631.                         END;
  632.  
  633.                         (* Blockbereich l”schen *)
  634.                         v.bool := EditBase.DeleteSomeLines (ed, oldStart.line, oldEnd.line);
  635.                         (* Alte gesicherte Zeile einfgen *)
  636.                         v.bool := EditBase.InsertLine (ed, oldStart.line, undoLine.text^, TRUE, LENGTH (undoLine.text^));
  637.                         whatToUndo := blockCut;
  638.                         currRow := oldStart.row;
  639.                         DEALLOCATE (undoLine.text, 0);
  640.                         block := FALSE;
  641.                         blocks[0].blockStart.line := -1;
  642.                         blocks[0].blockEnd.line := -1;
  643.                         
  644.                         |
  645.         ELSE
  646.         END (* CASE whatToUndo OF *);
  647.       END (* WITH undoBuffer *);
  648.       UpdateCurrLine (ed, currLineNr);
  649.       SetDocument (ed);
  650.     END; (* IF editChanged *)
  651.     currRow := BinOps.HigherInt (0, BinOps.LowerInt (editLen, currRow));
  652.     EditGlobals.FixCursorPos (ed);
  653.     (*
  654.     countLines();
  655.     *)
  656.     ed^.cursPos.row := -1;   (* Neue Positionsberechnung fr Cursor erzwingen *)
  657.     ShowFileChanged (ed);
  658.     WdwManager.RedrawWdw (ed^.wdw, ed^.editWork);
  659.     CenterCurrline (ed);
  660.     SetDocument (ed);
  661.   END;
  662.   ShowCursor (ed);
  663. END Undo;
  664.  
  665. PROCEDURE SaveOp (ed : EDITPTR; op : undoType; append : BOOLEAN);
  666.   VAR clLine,
  667.       blEnd,
  668.       lastLine : LONGINT;
  669.       clRow : INTEGER;
  670.       line  : aLinePtr;
  671.       argPtr : POINTER TO ARRAY[0..1] OF aMark;
  672. BEGIN
  673. (*        undoType   = (blockToChar, charToBlock, blockCut, cutUndo, blockPaste, normalPaste, lineDel, nothingToDo); *)
  674.   WITH ed^ DO
  675.     v.bool := EditBase.PutCurrLine (ed);
  676.     WITH undoBuffer DO
  677.       whatToUndo := op;
  678.       saveLineNr := -1;
  679.       undoBuffer.wdw := ed^.wdw;
  680.       CASE op OF
  681.         blockPaste,
  682.         blockCut,
  683.         blockToChar : IF (blocks[0].blockStart.line < 0) OR (blocks[0].blockEnd.line < 0) OR (blocks[0].blockEnd.line < blocks[0].blockStart.line) THEN RETURN END;
  684.                       (* alten Undobuffer freigeben, wird nicht mehr gebraucht! *)
  685.                       freeUndoBuffer ();
  686.                       (* Blockmarken merken *)
  687.                       oldStart := blocks[0].blockStart;
  688.                       oldEnd  := blocks[0].blockEnd;
  689.                       (* gesamten Block duplizieren *)
  690.                       IF blocks[0].blockEnd.line >= totalLineNr-1
  691.                       THEN
  692.                         blEnd := blocks[0].blockEnd.line;
  693.                         atEndOfText := TRUE;
  694.                       ELSE
  695.                         blEnd := blocks[0].blockEnd.line + 1;
  696.                         atEndOfText := FALSE; 
  697.                       END;
  698.                       IF ~EditBase.CopyToBuff (ed, blocks[0].blockStart.line, blEnd, buffer, bufSize)
  699.                       THEN
  700.                         whatToUndo := nothingToDo;
  701.                         freeUndoBuffer();
  702.                         RETURN
  703.                       END;
  704.                       (* Cursorposition restaurieren *)
  705.                       |
  706.         normalPaste : (* erstmal alten buffer freigeben, wird nicht mehr gebraucht
  707.                        *) 
  708.                       freeUndoBuffer ();
  709.                       (* Kann ich nicht so leicht machen, bessere Idee gehabt:
  710.                        * nachher noch einen Aufruf mit den entsprechenden Werten in den BlockMarken
  711.                        * Die sollten sowieso drin sein, da die auch bei blockPaste drinstehen mssen.
  712.                        *)
  713.                       (* Ich muž mir nur die aktuelle Zeile merken, falls die gesplittet wird *)
  714.                       (* currLine merken und undoBuffer darauf setzen! *)
  715.                       IF undoLine.text # NIL THEN DEALLOCATE (undoLine.text, 0) END;
  716.                       ALLOCATE (undoLine.text, editLine.length);
  717.                       IF undoLine.text = NIL
  718.                       THEN
  719.                         whatToUndo := nothingToDo;
  720.                         RETURN
  721.                       ELSE
  722.                         undoLine.length := editLine.length;
  723.                       END;
  724.                       Strings.Assign (editLine.text^, undoLine.text^, v.bool);
  725.                       newStart.line := currLineNr;
  726.                       newEnd.line := currLineNr;
  727.                       lines := 1;
  728.                       |
  729.       ELSE
  730.         (* empty ELSE for CASE *)
  731.       END (* CASE op OF *);
  732.     END;
  733.   END; (* WITH ed^ DO *)
  734. END SaveOp;
  735.  
  736. PROCEDURE NewBlockToUndoBuffer (VAR ed : EDITPTR);
  737. BEGIN
  738.   WITH ed^ DO 
  739.     WITH undoBuffer DO
  740.       CASE whatToUndo OF
  741.         blockPaste : newStart := blocks[0].blockStart; newEnd := blocks[0].blockEnd; |
  742.         normalPaste : oldStart := blocks[0].blockStart; oldEnd := blocks[0].blockEnd; |
  743.       ELSE
  744.       END; (* CASE *)
  745.     END;
  746.   END; 
  747. END NewBlockToUndoBuffer;
  748.  
  749. PROCEDURE PossibleUndo (ed: EDITPTR): BOOLEAN;
  750. BEGIN
  751.   RETURN ed^.editChanged OR ((ed^.wdw = undoBuffer.wdw) & (undoBuffer.whatToUndo # nothingToDo));
  752. END PossibleUndo;
  753.  
  754.         (* Blockfunktionen I *)
  755.  
  756. PROCEDURE SetBlockstart (VAR ed : EDITPTR);
  757.   VAR oldLine : LONGINT;
  758.       oldRow  : INTEGER;
  759.  
  760.   PROCEDURE Unmark();
  761.   BEGIN
  762.     WITH ed^ DO 
  763.       blocks[0].blockStart.line := oldLine;
  764.       blocks[0].blockStart.row := oldRow;
  765.       ShowBlockMark (ed, TRUE);
  766.       blocks[0].blockStart.line := currLineNr;
  767.       blocks[0].blockStart.row := currRow;
  768.     END;
  769.   END Unmark;
  770.  
  771. BEGIN
  772.   WITH ed^ DO 
  773.     IF multiBlockIdx > 0 THEN RETURN END;
  774.     WITH blocks[0].blockStart DO 
  775.       oldLine := line;
  776.       oldRow  := row;
  777.       line := currLineNr;
  778.       row  := currRow;
  779.     END;
  780.     IF blocks[0].blockEnd.line >= blocks[0].blockStart.line 
  781.     THEN 
  782.       IF oldLine >= 0
  783.       THEN
  784.         (* Block erweitern *)
  785.         Unmark();
  786.         ShowBlockMark (ed, TRUE);
  787.       ELSE
  788.         ShowBlockMark (ed, TRUE);
  789.       END;
  790.     ELSE
  791.       IF blocks[0].blockEnd.line >= oldLine
  792.       THEN 
  793.         (* alten Block l”schen *)
  794.         Unmark();
  795.       END;
  796.     END;
  797.   END; (* WITH ed^ DO *)
  798. END SetBlockstart;
  799.  
  800. PROCEDURE SetBlockend (VAR ed : EDITPTR);
  801.   VAR oldLine : LONGINT;
  802.       oldRow  : INTEGER;
  803.   
  804.   PROCEDURE Unmark();
  805.   BEGIN
  806.     WITH ed^ DO 
  807.       blocks[0].blockEnd.line := oldLine;
  808.       blocks[0].blockEnd.row := oldRow;
  809.       ShowBlockMark (ed, TRUE);
  810.       blocks[0].blockEnd.line := currLineNr;
  811.       blocks[0].blockEnd.row := currRow;
  812.     END;
  813.   END Unmark;
  814.   
  815. BEGIN
  816.   WITH ed^ DO 
  817.     IF multiBlockIdx > 0 THEN RETURN END;
  818.     WITH blocks[0].blockEnd DO 
  819.       oldLine := line;
  820.       oldRow  := row;
  821.       line := currLineNr;
  822.       row  := currRow;
  823.     END;
  824.     IF blocks[0].blockEnd.line >= blocks[0].blockStart.line 
  825.     THEN 
  826.       IF (oldLine >= 0) & (blocks[0].blockStart.line >= 0)
  827.       THEN
  828.         (* Block erweitern *)
  829.         Unmark;
  830.         ShowBlockMark (ed, TRUE);
  831.       ELSE
  832.         ShowBlockMark (ed, TRUE);
  833.       END;
  834.     ELSE
  835.       IF oldLine >= blocks[0].blockStart.line
  836.       THEN
  837.         (* alte Blockmarkierung l”schen *)
  838.         Unmark();
  839.       END;
  840.     END;
  841.   END; (* WITH ed^ DO *)
  842. END SetBlockend;
  843.  
  844. PROCEDURE ClearBlock (VAR ed : EDITPTR);
  845. (* L”scht Blockmarkierung *)
  846.   VAR i : INTEGER;
  847. BEGIN
  848.   ShowBlockMark (ed, TRUE);
  849.   WITH ed^ DO 
  850.     FOR i := 0 TO maxBlocks - 1 DO
  851.       WITH blocks[i] DO
  852.         blockStart.line := -1;
  853.         blockEnd.line := -1;
  854.       END;
  855.     END;
  856.     multiBlockIdx := -1;
  857.     block := FALSE;
  858.   END;
  859. END ClearBlock;
  860.  
  861. PROCEDURE GetClickLineAndRow (ed : EDITPTR; x, y : INTEGER; VAR clLine : LONGINT; VAR clRow : INTEGER);
  862. VAR extend    : ARRAY [0..3] OF Point;
  863.     ch  : ARRAY [0..1] OF CHAR;
  864.     saveCh : CHAR;
  865.     charAdr : POINTER TO CHAR;
  866.     sl:       INTEGER;
  867.     text:     textPtr;
  868.     i, j:     INTEGER;
  869.     takeLast: BOOLEAN;
  870.     xSub:     INTEGER;
  871. BEGIN
  872.   WITH ed^ DO 
  873.     (* Feststellen, in welche Zeile geklickt wurde *)
  874.     clLine := StartLine + LONG((y - editWork.y) DIV charHeight);
  875.     IF clLine < 0 THEN clLine := 0; clRow := 0; RETURN END;
  876.     IF clLine > totalLineNr - 1 THEN 
  877.       clLine := totalLineNr - 1;
  878.       takeLast := TRUE;
  879.     ELSE
  880.       takeLast := FALSE;
  881.     END;
  882.     (* Zeile zur aktuellen machen *)
  883.     SetCurrLine (ed, clLine);
  884.     (* Jetzt Spalte bestimmen *)
  885.     IF ~insertMode
  886.     THEN
  887.       IF monoSpaced THEN
  888.         xSub := charWidth DIV 2;
  889.       ELSE
  890.         xSub := 0;
  891.       END;
  892.     ELSE
  893.       xSub := 0;
  894.     END;
  895.     INC (x, pixOff);                                         (* PixelOffset addieren *)
  896.     clRow := (x + leftOffset - editWork.x-xSub) DIV charWidth;
  897.     
  898.     sl := editLen;
  899.     IF clRow < 0 THEN clRow := 0 END;
  900.     (* clRow ist nur N„herung, mal suchen gehen *)
  901.     IF takeLast THEN 
  902.       currRow := sl;
  903.       EditGlobals.FixCursorPos (ed);
  904.       clRow := currRow;
  905.       RETURN 
  906.     END;
  907.     IF realTabs
  908.     THEN
  909.       CatGlobal.ConvertTabs (editLine.text^, theDrawLine, tabSize);
  910.       text := ADR(theDrawLine);
  911.       sl := (*SYSTEM.*)LENGTH (text^);
  912.     ELSE
  913.       text := editLine.text;
  914.     END;
  915.     clRow :=BinOps.HigherInt (0, BinOps.LowerInt (clRow, sl));
  916.     IF x <= editWork.x THEN 
  917.       clRow := 0 (* Sonderfall! *)
  918.     ELSIF ~monoSpaced OR parseEffects
  919.     THEN
  920.       (* Nachsehen, ob berechnete Position zu klein! *)
  921.       REPEAT
  922.         IF (clRow < sl)
  923.         THEN
  924.           INC(clRow);
  925. (*
  926.           (* So geht's schneller: *)
  927.           charAdr := ADR (text^[clRow]);
  928.           saveCh := charAdr^;
  929.           (* String terminieren *)
  930.           charAdr^ := 0C;
  931.           (* Cursorposition bestimmen mit eigener Funktion wegen Attributen *)
  932.           InqTextextend (ed, text^, extend, TRUE);
  933.           (* Žnderung wieder rckg„ngig machen *)
  934.           charAdr^ := saveCh;
  935. *)
  936.           GetTextWidth (ed, text^, clRow, extend);
  937.         END;
  938.       UNTIL ((x-editWork.x+leftOffset) < (extend[1].x - extend[0].x)) OR (clRow >= sl); 
  939.       INC (clRow);
  940.       REPEAT
  941.         DEC (clRow);
  942.         IF (clRow > 0) & (clRow <= sl)
  943.         THEN
  944. (*
  945.           (* So geht's schneller: *)
  946.           charAdr := ADR (text^[clRow]);
  947.           saveCh := charAdr^;
  948.           (* String terminieren *)
  949.           charAdr^ := 0C;
  950.           (* Cursorposition bestimmen *)
  951.           InqTextextend (ed, text^, extend, TRUE);
  952.           (* Žnderung wieder rckg„ngig machen *)
  953.           charAdr^ := saveCh;
  954. *)
  955.           GetTextWidth (ed, text^, clRow, extend);
  956.         END;
  957.       UNTIL ((x-editWork.x+leftOffset) > (extend[1].x - extend[0].x)) OR (clRow = 0); 
  958.     END;
  959.     clRow := BinOps.LowerInt (clRow, sl);
  960.     IF realTabs
  961.     THEN
  962.       v.bool := EditBase.GetLineAdr (ed, currLineNr, text, sl);
  963.       j := 0;
  964.       i := 0;
  965.       WHILE j <= clRow DO
  966.         IF text^[i] = TAB
  967.         THEN
  968.           j := ((j DIV tabSize)+1)*tabSize;
  969.         ELSE
  970.           INC(j);
  971.         END;
  972.         INC(i);
  973.       END;
  974.       IF i > 0 THEN clRow := i-1 ELSE clRow := i; END;
  975.     END;
  976.     (* Jetzt noch CR abfangen *)
  977.     IF (clRow > 0) & (text^[clRow-1] = 15C)
  978.     THEN
  979.       DEC (clRow);
  980.     END;
  981.     currRow := clRow;
  982.     EditGlobals.FixCursorPos (ed);
  983.     clRow := currRow;
  984.   END (* WITH ed^ DO *)
  985. END GetClickLineAndRow;
  986.  
  987. PROCEDURE TestBlockMarksAndSwap (ed : EDITPTR);
  988.   CONST  wordEnds = CharSet {0C, 12C, 15C, ' ','.',',',';','!','-','?',':','"',"'",'}',']',')'};
  989.   VAR i, j : INTEGER;
  990.       bl   : INTEGER;
  991. BEGIN
  992.   WITH ed^ DO 
  993.     FOR bl := 0 TO maxBlocks - 1 DO
  994.       IF (blocks[bl].blockStart.line >= 0) & (blocks[bl].blockEnd.line >= 0)
  995.       THEN
  996.         IF blocks[bl].blockEnd.line < blocks[bl].blockStart.line
  997.         THEN
  998.           v.lint := blocks[bl].blockEnd.line;
  999.           blocks[bl].blockEnd.line := blocks[bl].blockStart.line;
  1000.           blocks[bl].blockStart.line := v.lint;
  1001.           v.int := blocks[bl].blockEnd.row;
  1002.           blocks[bl].blockEnd.row := blocks[bl].blockStart.row;
  1003.           blocks[bl].blockStart.row := v.int;
  1004.         ELSIF (blocks[bl].blockEnd.line = blocks[bl].blockStart.line) & (blocks[bl].blockEnd.row < blocks[bl].blockStart.row)
  1005.         THEN 
  1006.           v.int := blocks[bl].blockEnd.row;
  1007.           blocks[bl].blockEnd.row := blocks[bl].blockStart.row;
  1008.           blocks[bl].blockStart.row := v.int;
  1009.         END;
  1010.         (* Jetzt noch Spezialbehandlung fr Effekte *)
  1011.         IF parseEffects & (blocks[bl].blockStart.row > 0)
  1012.         THEN
  1013.           SetCurrLine (ed, blocks[bl].blockStart.line);
  1014.           IF editLine.text^[blocks[bl].blockStart.row-1] IN CharSet {'*','/','_'}
  1015.           THEN
  1016.             (* Check for second occurence of effect char in line *)
  1017.             i := blocks[bl].blockStart.row-1;
  1018.             j := i;
  1019.             REPEAT
  1020.               REPEAT
  1021.                 INC(j);
  1022.               UNTIL (j >= editLen) OR (editLine.text^[j] = editLine.text^[i]);
  1023.             UNTIL (j >= editLen) OR (editLine.text^[j+1] IN wordEnds);
  1024.             IF j < editLen
  1025.             THEN
  1026.               (* Ok, wirklich ein Effektzeichen, also hinzunehmen *)
  1027.               DEC (blocks[bl].blockStart.row);
  1028.             END;
  1029.           END;
  1030.         END;
  1031.       END;
  1032.     END;
  1033.   END;
  1034. END TestBlockMarksAndSwap;
  1035.  
  1036. PROCEDURE ToWordEnd (ed : EDITPTR; line : LONGINT; row : INTEGER) : INTEGER;
  1037. VAR l, z : INTEGER;
  1038.     text : textPtr;
  1039. BEGIN
  1040.   WITH ed^ DO
  1041.     IF ~EditBase.GetLineAdr (ed, line, text, l)
  1042.     THEN
  1043.       RETURN row
  1044.     END;
  1045.     IF (l > 0) & (text^[l-1] = 15C) THEN DEC (l) END;
  1046.     z := row;
  1047.     WHILE (z < l) & ~(text^[z] IN TrennSet) DO INC (z) END;
  1048.     IF (z < l) & (text^[z] IN CharSet{'*','/','_'}) THEN INC (z) END;
  1049.     RETURN z
  1050.   END;
  1051. END ToWordEnd;
  1052.  
  1053. PROCEDURE ToWordStart (ed : EDITPTR; line : LONGINT; row : INTEGER) : INTEGER;
  1054. VAR l, z   : INTEGER;
  1055.     text : textPtr;
  1056. BEGIN
  1057.   WITH ed^ DO
  1058.     IF ~EditBase.GetLineAdr (ed, line, text, l)
  1059.     THEN
  1060.       RETURN row
  1061.     END;
  1062.     z := BinOps.LowerInt (l, row);
  1063.     WHILE (z > 0) & ~(text^[z] IN TrennSet) DO DEC (z) END;
  1064.     IF (z # 0) & (z+1 < row) THEN INC(z); END; 
  1065. (*    IF (z+1 < row) THEN INC(z); END; *)
  1066.     IF (z > 0) & (text^[z-1] IN CharSet{'*','/','_'}) THEN DEC (z) END;
  1067.     RETURN z
  1068.   END;
  1069. END ToWordStart;
  1070.  
  1071. PROCEDURE ToLineStart (ed: EDITPTR; line: LONGINT): INTEGER;
  1072. BEGIN
  1073.   (* Ist nur gedacht fr andere m”gliche Implementationen, deshalb 
  1074.    * als Funktion
  1075.    *)
  1076.   RETURN 0;
  1077. END ToLineStart;
  1078.  
  1079. PROCEDURE ToLineEnd (ed: EDITPTR; line: LONGINT): INTEGER;
  1080. (* Gibt die Cursorposition fr das Zeilenende zurck *)
  1081.   VAR cRow,
  1082.       ret   : INTEGER;
  1083. BEGIN
  1084.   WITH ed^ DO
  1085.     cRow := currRow;
  1086.     IF EditBase.GetLineLength (ed, currLineNr, currRow)
  1087.     THEN
  1088.       EditGlobals.FixCursorPos (ed);
  1089.       ret := currRow;
  1090.     ELSE
  1091.       ret := cRow
  1092.     END;
  1093.     currRow := cRow;
  1094.   END;
  1095.   RETURN ret;
  1096. END ToLineEnd;
  1097.  
  1098. PROCEDURE MarkLine (ed : EDITPTR);
  1099.   VAR clRow,
  1100.       l : INTEGER;
  1101.       cLine: LONGINT;
  1102. BEGIN
  1103.   WITH ed^ DO
  1104.     clRow := currRow;
  1105.     currRow := 0;
  1106.     SetBlockstart (ed);
  1107.     IF currLineNr = totalLineNr - 1
  1108.     THEN
  1109.       v.bool := EditBase.GetLineLength (ed, currLineNr, currRow);
  1110.       EditGlobals.FixCursorPos (ed);
  1111.       SetBlockend (ed);
  1112.     ELSE
  1113.       cLine := currLineNr;
  1114.       SetCurrLine (ed, currLineNr+1);
  1115.       SetBlockend (ed);
  1116.       SetCurrLine (ed, cLine);
  1117.     END;
  1118.     currRow := clRow;
  1119.     block := TRUE;
  1120.   END; (* WITH ed^ DO *)
  1121. END MarkLine;
  1122.  
  1123. PROCEDURE MarkWord (VAR ed : EDITPTR);
  1124.   TYPE wordRange = (all, line);
  1125.   
  1126.   VAR clRow : INTEGER;
  1127.       clLine : LONGINT;
  1128.       opChar,
  1129.       ch     : CHAR;
  1130.       text   : textPtr;
  1131.       l, depth,
  1132.       i      : INTEGER;
  1133.       found  : BOOLEAN;
  1134.       dir    : searchDir;
  1135.       range  : wordRange;
  1136. BEGIN
  1137.   WITH ed^ DO 
  1138.     clRow := currRow;
  1139.     clLine := currLineNr;
  1140.     (* Feststellen, welches Zeichen unter Cursor ist *)
  1141.     ch := editLine.text^[currRow];
  1142.     found := FALSE;
  1143.     IF ch IN CharSet{'{','[','(','"',"'",')',']','}'}
  1144.     THEN (* Ist Klammerzeichen *)
  1145.       (* gegengesetztes Zeichen feststellen *)
  1146.       CASE ch OF
  1147.         '{' : opChar := '}'; dir := forward; range := all; |
  1148.         '}' : opChar := '{'; dir := backward; range := all; |
  1149.         '(' : opChar := ')'; dir := forward; range := all; |
  1150.         ')' : opChar := '('; dir := backward; range := all; |
  1151.         '[' : opChar := ']'; dir := forward; range := all; |
  1152.         ']' : opChar := '['; dir := backward; range := all; |
  1153.         "'",
  1154.         '"' : opChar := ch; range := line; |
  1155.       ELSE
  1156.       END;
  1157.       IF range = line
  1158.       THEN 
  1159.         (* nur aktuelle Zeile durchsuchen, vorrangig vorw„rts! *)
  1160.         text := editLine.text;
  1161.         l := editLen;
  1162.         INC(currRow);
  1163.         LOOP
  1164.           IF currRow >= l THEN EXIT END;
  1165.           IF text^[currRow] = opChar THEN found := TRUE; EXIT END;
  1166.           INC(currRow);
  1167.         END;
  1168.         IF ~found & (currRow > 0) THEN
  1169.           (* Rckw„rts suchen *)
  1170.           currRow := clRow -1;
  1171.           LOOP
  1172.             IF currRow < 0 THEN EXIT END;
  1173.             IF text^[currRow] = opChar THEN found := TRUE; EXIT END;
  1174.             DEC(currRow);
  1175.           END;
  1176.         END;
  1177.         IF ~found
  1178.         THEN currRow := clRow;
  1179.         ELSE
  1180.           block := TRUE;
  1181.           IF currRow < clRow THEN
  1182.             SetBlockstart (ed);
  1183.             currRow := clRow+1;
  1184.             SetBlockend (ed);
  1185.           ELSE
  1186.             INC (currRow);
  1187.             SetBlockend (ed);
  1188.             currRow := clRow;
  1189.             SetBlockstart (ed);
  1190.           END
  1191.         END;
  1192.       ELSE (* range = all *)
  1193.         depth := 0;
  1194.         IF dir = forward
  1195.         THEN
  1196.           INC(currRow);
  1197.           LOOP (* 1 *)
  1198.             text := editLine.text;
  1199.             l := editLen;
  1200.             LOOP (* 2, in Zeile *)
  1201.               IF (text^[currRow] = opChar)
  1202.               THEN
  1203.                 IF depth = 0
  1204.                 THEN found := TRUE; EXIT (* 2 *)
  1205.                 ELSE
  1206.                   DEC (depth);
  1207.                 END;
  1208.               ELSIF (text^[currRow] = ch)
  1209.               THEN
  1210.                 INC (depth);
  1211.               END;
  1212.               IF currRow >= l
  1213.               THEN EXIT (* 2 *)
  1214.               END;
  1215.               INC(currRow);
  1216.             END; (* LOOP 2 *)
  1217.             IF found THEN EXIT  (* 1 *) END;
  1218.             IF currLineNr = totalLineNr - 1 THEN EXIT (* 1 *)
  1219.             ELSE 
  1220.               SetCurrLine (ed, currLineNr + 1);
  1221.               currRow := 0;
  1222.             END;
  1223.           END; (* LOOP 1 *)
  1224.           IF found
  1225.           THEN
  1226.             INC (currRow);
  1227.             SetBlockend (ed);
  1228.             SetCurrLine (ed, clLine);
  1229.             currRow := clRow;
  1230.             SetBlockstart (ed);
  1231.             block := TRUE
  1232.           END;
  1233.         ELSE (* dir = backward *)  
  1234.           DEC (currRow); 
  1235.           text := editLine.text;
  1236.           LOOP (* 1 *)
  1237.             LOOP (* 2, in Zeile *)
  1238.               IF currRow < 0
  1239.               THEN EXIT (* 2 *)
  1240.               END;
  1241.               IF (text^[currRow] = opChar)
  1242.               THEN
  1243.                 IF depth = 0
  1244.                 THEN found := TRUE; EXIT (* 2 *)
  1245.                 ELSE
  1246.                   DEC (depth);
  1247.                 END;
  1248.               ELSIF (text^[currRow] = ch)
  1249.               THEN
  1250.                 INC (depth);
  1251.               END;
  1252.               DEC(currRow);
  1253.             END; (* LOOP 2 *)
  1254.             IF found THEN EXIT  (* 1 *) END;
  1255.             IF currLineNr = 0 THEN EXIT (* 1 *)
  1256.             ELSE 
  1257.               SetCurrLine (ed, currLineNr - 1);
  1258.               l := editLen;
  1259.               WHILE (l>0) & (ORD(text^[l-1]) < 20) DO DEC (l) END;
  1260.               IF l > 0 THEN currRow := l-1 ELSE currRow := l; END;
  1261.             END;
  1262.           END;
  1263.           IF found
  1264.           THEN
  1265.             SetBlockstart (ed);
  1266.             SetCurrLine (ed, clLine);
  1267.             currRow := clRow+1;
  1268.             SetBlockend (ed);
  1269.             block := TRUE
  1270.           END;
  1271.         END; (* IF dir *)
  1272.       END; (* IF range *)
  1273.     END; (* IF ch IN klammern *)
  1274.     IF ~found
  1275.     THEN
  1276.       SetCurrLine (ed, clLine);
  1277.       currRow := clRow;
  1278.       currRow := ToWordEnd (ed, currLineNr, currRow);
  1279.       SetBlockend (ed);
  1280.       IF currRow > 0 THEN DEC (currRow) END;
  1281.       currRow := ToWordStart (ed, currLineNr, currRow);
  1282.       SetBlockstart (ed);
  1283.       block := TRUE;
  1284.     END;
  1285.   END (* WITH ed^ DO *);
  1286. END MarkWord;
  1287.   
  1288. PROCEDURE MarkBlock (VAR ed : EDITPTR; ox, oy : INTEGER; init: BOOLEAN; fromTop: BOOLEAN);
  1289. (* Wird mit gedrckter linker Taste aufgerufen, bernimmt die Blockmarkierung 
  1290.  *)
  1291. VAR 
  1292.     b       : BITSET;
  1293.     mouse   : BOOLEAN;
  1294.     clip, 
  1295.     work    : Rectangle;
  1296.     newLine,
  1297.     oldLine : LONGINT;
  1298.     oldX,
  1299.     oldY,
  1300.     charX,
  1301.     charY,
  1302.     oldRow,
  1303.     oldPixRow,
  1304.     newPixRow,
  1305.     newRow  : INTEGER;
  1306.     newEnd,
  1307.     newStart,
  1308.     saveEnd,
  1309.     saveStart : aMark;
  1310.     mx, my  : INTEGER;
  1311.     blockRects : ARRAY [0..2] OF Rectangle;
  1312.     i, j    : INTEGER;
  1313.     lines   : INTEGER;
  1314.     isRight,
  1315.     isLeft,
  1316.     oldIsRight,
  1317.     oldIsLeft   : BOOLEAN;
  1318.     
  1319. BEGIN
  1320.   (* Arbeitsweise: Invertiert den von der Maus berstrichenen Bereich und scrollt notfalls das Fenster.
  1321.    * Dabei wird jeweils der Block neu festgestellt, damit das auch beim Scrollen noch funktioniert.
  1322.    *)
  1323.   WITH ed^ DO 
  1324.     (* Erst mal die Maus anschalten und auf Textcursor setzen *)
  1325.     SaveMouse;
  1326.     MouseCursor;
  1327.     ShowMouse (TRUE);
  1328.     MagicAES.WindUpdate (MagicAES.BEGMCTRL);    (* Wir haben jetzt die komplette Mauskontrolle          *)
  1329.     ClipWork (ed);                              (* Clipping auf Work-bereich vom Editor legen           *)
  1330.     work := editWork;                           (* Work-Bereich als xy-Paar berechnen                   *)
  1331.     work.w := work.x + work.w - 1;
  1332.     work.h := work.y + work.h - 1;
  1333.     GetClickLineAndRow (ed, ox, oy, oldLine, oldRow);
  1334.     newStart := blocks[0].blockStart;
  1335.     newEnd   := blocks[0].blockEnd;
  1336.     IF init 
  1337.     THEN 
  1338.       saveStart:= blocks[0].blockStart;
  1339.       saveEnd  := blocks[0].blockEnd;
  1340.     ELSE
  1341.       IF fromTop
  1342.       THEN
  1343.         saveStart:= blocks[0].blockStart;
  1344.         oldRow := blocks[0].blockEnd.row;
  1345.         oldLine := blocks[0].blockEnd.line;
  1346.         IF wordBlock
  1347.         THEN
  1348.           saveEnd.line := saveStart.line; 
  1349.           saveEnd.row := ToWordEnd (ed, saveEnd.line, saveStart.row);
  1350.         ELSIF lineBlock
  1351.         THEN
  1352.           IF saveStart.line < totalLineNr - 1
  1353.           THEN
  1354.             saveEnd.line := saveStart.line + 1;
  1355.             saveEnd.row := ToLineStart (ed, saveEnd.line);
  1356.           ELSE
  1357.             saveEnd.line := saveStart.line;
  1358.             saveEnd.row := ToLineEnd (ed, saveEnd.line);
  1359.           END;
  1360.         END;
  1361.       ELSE
  1362.         saveEnd:= blocks[0].blockEnd;
  1363.         oldRow := blocks[0].blockStart.row;
  1364.         oldLine := blocks[0].blockStart.line;
  1365.         IF wordBlock
  1366.         THEN
  1367.           saveStart.line := saveEnd.line; 
  1368.           saveStart.row := ToWordStart (ed, saveStart.line, saveEnd.row);
  1369.           IF (saveStart.row = saveEnd.row) & (saveStart.row > 0)
  1370.           THEN
  1371.             saveStart.row := ToWordStart (ed, saveStart.line, saveStart.row - 1);
  1372.           END;
  1373.         ELSIF lineBlock
  1374.         THEN
  1375.           IF saveEnd.line > 0
  1376.           THEN
  1377.             saveStart.line := saveEnd.line - 1;
  1378.             saveStart.row := ToLineStart (ed, saveStart.line);
  1379.           ELSE
  1380.             saveStart.line := 0;
  1381.             saveStart.row := ToLineStart (ed, saveStart.line);
  1382.           END;
  1383.         END;
  1384.       END;
  1385.     END;
  1386.     getCharPos (ed, oldLine, oldRow, oldPixRow, v.int);
  1387.     MagicAES.GrafMkstate (mx, my, b, v.bset); 
  1388.     REPEAT 
  1389.       IF my < work.y
  1390.       THEN 
  1391.         (* Oberhalb vom Work-Bereich, scrollen *)
  1392.         (* Und jetzt scrollen, eigentlich sollte der Rest funktionieren *)
  1393.         IF my + 2*charHeight < work.y
  1394.         THEN lines := 5
  1395.         ELSIF my + charHeight  < work.y
  1396.         THEN lines := 3
  1397.         ELSE lines := 1;
  1398.         END;
  1399.         HideMouse();
  1400.         WdwManager.ScrollUp (ed^.wdw, lines);
  1401.         ShowMouse(FALSE);
  1402.       ELSIF my > work.h
  1403.       THEN 
  1404.         (* Unterhalb von Work-Bereich, scrollen *)
  1405.         IF my - 2*charHeight > work.h 
  1406.         THEN lines := 5
  1407.         ELSIF my - charHeight > work.h 
  1408.         THEN lines := 3
  1409.         ELSE lines := 1
  1410.         END;
  1411.         HideMouse();
  1412.         WdwManager.ScrollDown (ed^.wdw, lines);
  1413.         ShowMouse (FALSE);
  1414.       END;
  1415.       IF (mx <= work.x) OR (mx <= 0)
  1416.       THEN 
  1417.         (* Nach links scrollen *)
  1418.         IF (mx + 2*charWidth <= work.x)
  1419.         THEN lines := 5
  1420.         ELSIF (mx + charWidth <= work.x)
  1421.         THEN lines := 3
  1422.         ELSE lines := 1
  1423.         END;
  1424.         WdwManager.ScrollLeft (ed^.wdw, lines);
  1425.       ELSIF mx > work.w 
  1426.       THEN 
  1427.         (* Nach rechts scrollen *)
  1428.         IF (mx - 2*charWidth > work.w)
  1429.         THEN lines := 5
  1430.         ELSIF (mx - charWidth > work.w)
  1431.         THEN lines := 3
  1432.         ELSE lines := 1
  1433.         END;
  1434.         WdwManager.ScrollRight (ed^.wdw, lines);
  1435.       END; (* Bewegungsauswertung *)
  1436.       (* So, jetzt k”nnte es funktionieren *)
  1437.       GetClickLineAndRow (ed, mx, my, newLine, newRow);
  1438.       (* Jetzt haben wir Zeile und Spalte. Jetzt mssen noch die Nebenbedingungen
  1439.        * beachtet werden, d.h. Wort- bzw. Zeilenmarkierung
  1440.        * und das mindestens ein Wort bzw. eine Zeile markiert bleibt!
  1441.        *)
  1442.       IF wordBlock 
  1443.       THEN
  1444.         (* Wordposition berechnen *)
  1445.         IF (newLine > saveStart.line) OR ((newLine = saveStart.line) & (newRow > saveStart.row))
  1446.         THEN
  1447.           newRow := ToWordEnd (ed, newLine, newRow);
  1448.         ELSE
  1449.           newRow := ToWordStart (ed, newLine, newRow);
  1450.         END;
  1451.       ELSIF lineBlock
  1452.       THEN
  1453.         (* Zeilenposition neu berechnen *)
  1454.         IF (newLine > saveStart.line)
  1455.         THEN
  1456.           INC (newLine);
  1457.         END;
  1458.         IF newLine >= totalLineNr 
  1459.         THEN
  1460.           newRow := ToLineEnd (ed, totalLineNr-1);
  1461.           newLine := totalLineNr - 1;
  1462.         ELSE
  1463.           newRow := 0;
  1464.         END;
  1465.       END;
  1466.       newLine := BinOps.LowerLInt (totalLineNr-1, BinOps.HigherLInt (0, newLine));
  1467.       (* Jetzt feststellen, welche Marke neu gesetzt wird *)
  1468.       isRight := (newLine < saveStart.line) OR ((newLine = saveStart.line) & (newRow < saveStart.row));
  1469.       isLeft := (newLine > saveEnd.line) OR ((newLine = saveEnd.line) & (newRow > saveEnd.row));
  1470.       oldIsRight := (oldLine < saveStart.line) OR ((oldLine = saveStart.line) & (oldRow < saveStart.row));
  1471.       oldIsLeft := (oldLine > saveEnd.line) OR ((oldLine = saveEnd.line) & (oldRow > saveEnd.row));
  1472.       (* Jetzt haben wir die neuen Positionen, jetzt daraus die neuen 
  1473.        * Pixelpositionen berechnen und dann vergleichen 
  1474.        *)
  1475.       
  1476.       getCharPos (ed, newLine, newRow, newPixRow, v.int);
  1477.       IF isRight
  1478.       THEN
  1479.         IF oldIsRight
  1480.         THEN
  1481.           (* Einfach neuen Bereich markieren *)
  1482.           IF ((oldRow # newRow) OR (oldLine # newLine))(* & (oldLine >= 0) & (oldLine <= totalLineNr) *)
  1483.           THEN
  1484.             (* Es hat sich was ge„ndert, also mal neu zeichnen *)
  1485.             MarkArea (ed, oldLine, oldRow, newLine, newRow, TRUE);
  1486.           END;
  1487.         ELSIF oldIsLeft
  1488.         THEN
  1489.           (* Jetzt wird's spažiger, aber es hat sich garantiert was ge„ndert! 
  1490.            *)
  1491.           MarkArea (ed, oldLine, oldRow, saveEnd.line, saveEnd.row, TRUE);
  1492.           MarkArea (ed, newLine, newRow, saveStart.line, saveStart.row, TRUE);
  1493.           newEnd.line := saveEnd.line;
  1494.           newEnd.row := saveEnd.row;
  1495.         ELSE
  1496.           (* Markieren von Blockanfang bis zu neuem Anfang *)
  1497.           MarkArea (ed, newLine, newRow, saveStart.line, saveStart.row, TRUE);
  1498.         END;
  1499.         newStart.row := newRow;
  1500.         newStart.line := newLine;
  1501.       ELSIF isLeft
  1502.       THEN
  1503.         IF oldIsLeft 
  1504.         THEN
  1505.           (* Einfach neuen Bereich markieren *)
  1506.           IF ((oldRow # newRow) OR (oldLine # newLine))(* & (oldLine >= 0) & (oldLine <= totalLineNr) *)
  1507.           THEN
  1508.             (* Es hat sich was ge„ndert, also mal neu zeichnen *)
  1509.             MarkArea (ed, oldLine, oldRow, newLine, newRow, TRUE);
  1510.           END;
  1511.         ELSIF oldIsRight
  1512.         THEN
  1513.           (* Jetzt wird's spažiger, aber es hat sich garantiert was ge„ndert! 
  1514.            *)
  1515.           MarkArea (ed, oldLine, oldRow, saveStart.line, saveStart.row, TRUE);
  1516.           MarkArea (ed, newLine, newRow, saveEnd.line, saveEnd.row, TRUE);
  1517.           newStart.line := saveStart.line;
  1518.           newStart.row := saveStart.row;
  1519.         ELSE
  1520.           (* Markieren von Blockende bis zu neuer Position *)
  1521.           MarkArea (ed, newLine, newRow, saveEnd.line, saveEnd.row, TRUE);
  1522.         END;
  1523.         newEnd.row := newRow;
  1524.         newEnd.line := newLine;
  1525.       ELSE 
  1526.         (* in saveArea! *)
  1527.         IF oldIsRight
  1528.         THEN
  1529.           (* Bis zum Rand der Savearea markieren *)
  1530.           MarkArea (ed, oldLine, oldRow, saveStart.line, saveStart.row, TRUE);
  1531.           newStart.line := saveStart.line;
  1532.           newStart.row := saveStart.row;
  1533.         ELSIF oldIsLeft
  1534.         THEN
  1535.           MarkArea (ed, oldLine, oldRow, saveEnd.line, saveEnd.row, TRUE);
  1536.           newEnd.line := saveEnd.line;
  1537.           newEnd.row := saveEnd.row;
  1538.         ELSE 
  1539.           (* old ist ebenfalls in SaveArea, do nothing! *)
  1540.         END;
  1541.       END;
  1542.       (* jetzt alte Werte sichern *)
  1543.       oldLine := newLine;
  1544.       oldRow := newRow;
  1545.       oldPixRow := newPixRow;
  1546.       blocks[0].blockStart := newStart;
  1547.       blocks[0].blockEnd   := newEnd;
  1548.       MagicAES.GrafMkstate (mx, my, b, v.bset); 
  1549.     UNTIL ~(0 IN b);
  1550.     RestoreMouse();
  1551.     MagicAES.WindUpdate (MagicAES.ENDMCTRL);    (* Mauskontrolle wieder freigeben       *)
  1552.     ClipWork (ed);                              (* Und clipping wieder auf Workbereich  *)
  1553.     block := TRUE;
  1554.   END (* WITH ed^ *);
  1555. END MarkBlock;
  1556.  
  1557. PROCEDURE ToBlockmark (ed : EDITPTR; ende : BOOLEAN); 
  1558.   VAR newLine : LONGINT;
  1559.       dir     : INTEGER;
  1560.       diff    : INTEGER;
  1561. BEGIN
  1562.   WITH ed^ DO
  1563.     IF ~block THEN RETURN END;
  1564.     HideMouse(); 
  1565.     HideCursor (ed);
  1566.     IF ende THEN
  1567.       SetCurrLine (ed, blocks[0].blockEnd.line);
  1568.       currRow := blocks[0].blockEnd.row;
  1569.     ELSE (* IF Ende *)
  1570.       SetCurrLine (ed, blocks[0].blockStart.line);
  1571.       currRow := blocks[0].blockStart.row;
  1572.     END;
  1573.     CenterCurrline (ed);
  1574.     ShowCursor(ed);
  1575.     ShowMouse (FALSE);
  1576.   END (* WITH ed^ DO *);
  1577. END ToBlockmark;
  1578.  
  1579.         (* Suchen und Ersetzen      *)
  1580.         
  1581.         (* Basisfunktionen fr Search and Replace *)
  1582.  
  1583. PROCEDURE InitSearch (ed: EDITPTR; direction: searchDir;
  1584.                       VAR search, repl: ARRAY OF CHAR; doRepl: BOOLEAN): BOOLEAN; 
  1585. (* Compiliert das Suchmuster und setzt ein paar Variablen fr
  1586.  * Suchen & Ersetzen mit Wildcards, falls ersetzt werden soll
  1587.  * Gibt zurck, ob das Muster compiliert werden konnte.
  1588.  *)
  1589.  VAR
  1590.       gross:    BOOLEAN;
  1591.       up:       BOOLEAN;
  1592.       M:        INTEGER;
  1593.       i:        INTEGER;
  1594.       oneC,
  1595.       allC,
  1596.       wildC:    INTEGER;
  1597. BEGIN
  1598.   IF searchInited THEN EndSearch() END;
  1599.   M := (*SYSTEM.*)LENGTH (search); (* Anzahl der Zeichen im Suchstring *)
  1600.  
  1601.   (* Jetzt erstmal alle Wildcardzeichen am Anfang und am Ende l”schen,
  1602.    * die sind berflssig
  1603.    *)
  1604.   
  1605.   WHILE ((search [0] = EditTypes.wildOneChar) 
  1606.          OR (search [0] = EditTypes.wildAllChar)) DO
  1607.     Strings.Delete (search, 0, 1, v.bool);
  1608.   END;
  1609.   M := (*SYSTEM.*)LENGTH (search); (* Anzahl der Zeichen im Suchstring *)
  1610.   WHILE (M > 1) & ((search[M-1] = EditTypes.wildAllChar) OR (search[M-1] = EditTypes.wildOneChar)) DO
  1611.     search[M-1] := 0c; DEC (M);
  1612.   END;
  1613.  
  1614.   M := (*SYSTEM.*)LENGTH (search); (* Anzahl der Zeichen im Suchstring *)
  1615.  
  1616.   IF M = 0 THEN RETURN FALSE END;
  1617.  
  1618.   up := direction = backward;
  1619.   (* Soll grož = klein sein? Wenn nicht gesetzt, dann ja! *)
  1620.   gross := (GrossKlein IN ed^.findMode);
  1621.   
  1622.   (* Suchmuster compilieren *)
  1623.   pPatt := Find2.Compile (search, EditTypes.wildOneChar, 1C, EditTypes.wildAllChar, 12C, gross, up);
  1624.   
  1625.   IF doRepl
  1626.   THEN
  1627.     (* Nach Wildcards im Suchstring suchen und Positionen merken *)
  1628.     oneC := 0;
  1629.     allC := 0;
  1630.     wildC := 1;
  1631.     FOR i := 0 TO M-1 DO
  1632.       IF search[i] = EditTypes.wildOneChar
  1633.       THEN
  1634.         oneWildNumbers[oneC] := wildC;
  1635.         INC (oneC);
  1636.         INC (wildC);
  1637.       ELSIF search[i] = EditTypes.wildAllChar
  1638.       THEN
  1639.         allWildNumbers[allC] := wildC;
  1640.         INC (allC);
  1641.         INC (wildC);
  1642.       END;
  1643.     END;
  1644.   END;
  1645.   searchInited := TRUE;
  1646.   RETURN pPatt # NIL;
  1647. END InitSearch;
  1648.  
  1649. PROCEDURE SearchWord (ed : EDITPTR; w: ARRAY OF CHAR; 
  1650.                       direction : searchDir; VAR gefunden: BOOLEAN;
  1651.                       VAR foundWord: ARRAY OF CHAR; again : BOOLEAN);
  1652. (* Neue Suchroutine, benutzt jetzt Find-Modul von Andreas Alich. Reine Stringsuche
  1653.  * also ausgelagert.
  1654.  *)
  1655.  
  1656. VAR   
  1657.       startx:   INTEGER;               (* Position, ab der in der
  1658.                                            Zeile gesucht werden soll *)
  1659.       findx:    INTEGER;               (* gefundene Position *)
  1660.       gross:    BOOLEAN;
  1661.       up:       BOOLEAN;
  1662.       
  1663.       M, j:     INTEGER;        (* M: Laenge des Suchstrings *)
  1664.       L:        INTEGER;        (* Laenge der untersuchten Zeile *)
  1665.       found:    BOOLEAN;        (* Suchstring gefunden? *)
  1666.       cLine:    LONGINT;        (* tempor„re Variable fr gefundene Zeilennummer *)
  1667.       cRow:     INTEGER;        (* tempor„re Variable fr gefundene Spaltennummer *)
  1668.       saveLine: LONGINT;
  1669.       saveRow : INTEGER;
  1670.  
  1671.   PROCEDURE WortTest (VAR s: ARRAY OF CHAR; cRow : INTEGER; wLen : INTEGER): BOOLEAN;
  1672.   VAR   links, rechts:  BOOLEAN;
  1673.   (* findx ist die Startposition des Suchstrings, findx + wLen - 1 die Endp. *)
  1674.   (* L ist die Laenge der untersuchten Zeile *)
  1675.   BEGIN
  1676.     IF ~(NurWort IN ed^.findMode) THEN
  1677.       RETURN TRUE;
  1678.     ELSE
  1679.       links := (cRow = 0) OR (s [cRow] IN TrennSet) OR
  1680.                (s [cRow - 1] IN TrennSet);
  1681.       IF ~links THEN RETURN FALSE
  1682.       ELSE
  1683.         rechts := (cRow + wLen > ed^.editLen) OR
  1684.                   (s [cRow + wLen - 1] IN TrennSet) OR
  1685.                   (s [cRow + wLen] IN TrennSet);
  1686.         RETURN rechts;
  1687.       END (* inneres IF *);
  1688.     END (* IF *);
  1689.   END WortTest;
  1690.  
  1691. VAR     d:      CHAR;
  1692.  
  1693. BEGIN (* SucheWort *)
  1694.   mtAppl.MouseOff();
  1695.   ClearBlock (ed);
  1696.   mtAppl.MouseOn();
  1697.   up := direction = backward;
  1698.   
  1699.   IF ~searchInited THEN gefunden := FALSE END;
  1700.  
  1701.   WITH ed^ DO
  1702.     (* Suchen in neuem Editor: 
  1703.      * Suchen in jedem Buffer, ggf. Startposition und Buffer berechnen, 
  1704.      * falls ab aktueller Zeile. 
  1705.      * Wenn gefunden, dann nachprfen, ob gltig (in Block),
  1706.      * dann aus Offset Zeile und Spalte berechnen.
  1707.      *)
  1708.     saveLine := currLineNr;
  1709.     saveRow := currRow;
  1710.     startx := EditBase.GetOffset (ed);
  1711.     IF again THEN 
  1712.       IF up THEN
  1713.         DEC (startx);
  1714.         IF startx < 0 THEN startx := 0; END;
  1715.       ELSE
  1716.         INC (startx) 
  1717.       END;
  1718.     END;
  1719.     IF up 
  1720.     THEN
  1721.       L := startx;
  1722.     ELSE
  1723.       L := currentBuff^.usedMem;
  1724.     END;
  1725.     found := FALSE;
  1726.     LOOP
  1727.       IF Find2.Find (currentBuff^.buffer, L, pPatt, startx)
  1728.       THEN
  1729.         (* neu:  
  1730.     Falls das Muster gefunden wurde, sind die Eintr„ge 'len' und 'pMatch'
  1731.     in den tPat-Records gltig. 'pMatch' zeigt auf den Anfang des zum
  1732.     Teilmuster passenden Textteils. 'len' gibt die L„nge des Teilmusters an.
  1733.         *)
  1734.         findx := INTEGER(SHORT (LONGINT(ADDRESS(pPatt^.pFirst^.pMatch)-ADDRESS(currentBuff^.buffer))));
  1735.         
  1736.         EditBase.GetPos (ed, findx, cLine, cRow);
  1737.         SetCurrLine (ed, cLine);
  1738.         currRow := cRow;
  1739.         (* So, jetzt die L„nge des gefundenen Testes rausfinden und dann den Worttest machen! *)
  1740.         ptrPatt := pPatt^.pFirst;
  1741.         WHILE ptrPatt # NIL DO
  1742.           findx := INTEGER(SHORT (LONGINT(ADDRESS(ptrPatt^.pMatch)-ADDRESS(currentBuff^.buffer))));
  1743.           EditBase.GetPos (ed, findx, cLine, cRow);
  1744.           INC (cRow, INTEGER(ptrPatt^.len));
  1745.           ptrPatt := ptrPatt^.pNext;
  1746.         END;
  1747.         Strings.Copy (editLine.text^, currRow, cRow - currRow, foundWord, v.bool);
  1748.         IF WortTest (editLine.text^, currRow, cRow - currRow) THEN 
  1749.           found := TRUE; EXIT 
  1750.         END;
  1751.         findx := INTEGER(SHORT (LONGINT(ADDRESS(pPatt^.pFirst^.pMatch)-ADDRESS(currentBuff^.buffer))));
  1752.         IF up 
  1753.         THEN
  1754.           startx := findx-1;
  1755.           IF startx < 0 THEN startx := 0; END;
  1756.         ELSE
  1757.           startx := findx+1;
  1758.         END;
  1759.       ELSE
  1760.         (* Nicht in dem Buffer gefunden *)
  1761.         IF up THEN 
  1762.           IF currentBuff^.prev # NIL
  1763.           THEN
  1764.             currentBuff := currentBuff^.prev;
  1765.             startx := currentBuff^.usedMem;
  1766.             L := currentBuff^.usedMem;
  1767.           ELSE
  1768.             EXIT
  1769.           END;
  1770.         ELSE
  1771.           IF currentBuff^.next # NIL
  1772.           THEN
  1773.             currentBuff := currentBuff^.next;
  1774.             startx := 0;
  1775.             L := currentBuff^.usedMem;
  1776.           ELSE
  1777.             EXIT
  1778.           END;
  1779.         END;
  1780.       END;
  1781.     END (* LOOP *);
  1782.   
  1783.     IF found 
  1784.     THEN
  1785.       IF ~(silent IN findMode)
  1786.       THEN 
  1787.         mtAppl.MouseOff();
  1788.         (* Nicht globales Ersetzen, also Block markieren! *)
  1789.         SetBlockstart (ed);
  1790.         cRow := currRow;
  1791.         ptrPatt := pPatt^.pFirst;
  1792.         WHILE ptrPatt # NIL DO
  1793.           findx := INTEGER(SHORT (LONGINT(ADDRESS(ptrPatt^.pMatch)-ADDRESS(currentBuff^.buffer))));
  1794.           EditBase.GetPos (ed, findx, cLine, currRow);
  1795.           INC (currRow, INTEGER(ptrPatt^.len));
  1796.           ptrPatt := ptrPatt^.pNext;
  1797.         END;
  1798.         SetBlockend (ed);
  1799.         currRow := cRow;
  1800.         block := TRUE;
  1801.         CenterCurrline (ed);
  1802.         mtAppl.MouseOn();
  1803.       END;
  1804.     ELSE
  1805.       SetCurrLine (ed, saveLine);
  1806.       currRow := saveRow;
  1807.     END;
  1808.     gefunden := found;
  1809.   END (* WITH *);
  1810. END SearchWord;
  1811.  
  1812. PROCEDURE ReplaceWord (ed : EDITPTR; VAR s, t: ARRAY OF CHAR);
  1813. VAR     Zeile:  aLineDesc;
  1814.         sl, tl,
  1815.         zl, el: INTEGER;
  1816. (*$Reg*)tmpRow: INTEGER;
  1817.         i:      INTEGER;
  1818.         replW:  ARRAY [0..1023] OF CHAR;    (* L„nger kann unser Ersatzwort halt nicht werden *)
  1819.         numC:   CHAR;
  1820.         wIdx,
  1821.         pIdx,
  1822.         idx:    INTEGER;
  1823.         findx:  INTEGER;
  1824.         cLine:  LONGINT;
  1825.         cRow,
  1826.         clRow:  INTEGER;
  1827. BEGIN
  1828.   (* Erstmal Wildcards in t durch richtige Zeichen ersetzen *)
  1829.   tl := (*SYSTEM.*)LENGTH (t);
  1830.   tmpRow := 0;
  1831.   i := 0;
  1832.   WHILE i < tl DO
  1833.     IF (t[i] = EditTypes.wildOneChar)
  1834.     OR (t[i] = EditTypes.wildAllChar)
  1835.     THEN
  1836.       (* Ein-Zeichen-Wildcard gefunden *)
  1837.       numC := t[i+1];
  1838.       IF (numC >= '0') & (numC <= '9')
  1839.       THEN
  1840.         wIdx := INTEGER(ORD (numC) - ORD ('0'));
  1841.         (* Jetzt den Index in Patternliste rausfinden *)
  1842.         IF t[i] = EditTypes.wildOneChar
  1843.         THEN
  1844.           idx := oneWildNumbers[wIdx];
  1845.         ELSE
  1846.           idx := allWildNumbers[wIdx];
  1847.         END;
  1848.         INC (i);    (* Damit das Indexzeichen auch bersprungen wird *)
  1849.         (* Jetzt zum Ende des vorhergehenden Patterns gehen und dann 
  1850.          * alle Zeichen bis zum Anfang des n„chsten Patterns in das Replaceword
  1851.          * setzen 
  1852.          *)
  1853.  
  1854.         ptrPatt := pPatt^.pFirst;
  1855.         pIdx := 0;
  1856.         WHILE (ptrPatt # NIL) & (pIdx < idx) DO
  1857.           findx := INTEGER(SHORT (LONGINT(ADDRESS(ptrPatt^.pMatch)-ADDRESS(ed^.currentBuff^.buffer))));
  1858.           EditBase.GetPos (ed, findx, cLine, cRow);
  1859.           INC (cRow, INTEGER(ptrPatt^.len));
  1860.           ptrPatt := ptrPatt^.pNext;
  1861.           INC (pIdx);
  1862.         END;
  1863.         (* Jetzt haben wir die Position im Text, jetzt mssen wir nur noch herausfinden,
  1864.          * wieviele Zeichen wir kopieren k”nnen. Da es alles in einer Zeile ist,
  1865.          * kann ich zum rauskopieren auf editLine.text^ zugreifen!
  1866.          *)
  1867.         IF (ptrPatt # NIL)
  1868.         THEN
  1869.           (* Endposition steht praktisch schon in ptrPatt drin, muž nur ausgelesen
  1870.            * werden
  1871.            *)
  1872.           findx := INTEGER(SHORT (LONGINT(ADDRESS(ptrPatt^.pMatch)-ADDRESS(ed^.currentBuff^.buffer))));
  1873.           EditBase.GetPos (ed, findx, cLine, clRow);
  1874.           WHILE cRow < clRow DO
  1875.             replW[tmpRow] := ed^.editLine.text^[cRow];
  1876.             INC (cRow); INC (tmpRow);
  1877.           END;
  1878.         END;
  1879.       ELSE
  1880.         replW[tmpRow] := t[i];
  1881.         INC (tmpRow);
  1882.       END;
  1883.     ELSE
  1884.       replW[tmpRow] := t[i];
  1885.       INC (tmpRow);
  1886.     END;
  1887.     INC (i);
  1888.   END;
  1889.   replW[tmpRow] := 0c;
  1890.  
  1891.   (* ersetzt s durch replW in Zeile *)
  1892.   sl := (*SYSTEM.*)LENGTH (s);
  1893.   tl := (*SYSTEM.*)LENGTH (replW);
  1894.   WITH ed^ DO
  1895.     tmpRow := currRow;
  1896.     zl := editLen;
  1897.     el := zl + tl - sl;
  1898.     IF el >= editLine.length-1
  1899.     THEN
  1900.       el := ((el+16) DIV 16) * 16;
  1901.       IF el < 16 THEN el := 16 END;
  1902.       ALLOCATE (Zeile.text, el);
  1903.       IF Zeile.text = NIL
  1904.       THEN RETURN END;
  1905.       Zeile.length := el;
  1906.       Strings.Assign (editLine.text^, Zeile.text^, v.bool);
  1907.       Strings.Delete (Zeile.text^, tmpRow, sl, v.bool);
  1908.       Strings.Insert (replW, tmpRow, Zeile.text^, v.bool);
  1909.     ELSE
  1910.       WITH editLine DO 
  1911.         Strings.Delete (text^, tmpRow, sl, v.bool);
  1912.         Strings.Insert (replW, tmpRow, text^, v.bool);
  1913.       END;
  1914.       el := -1
  1915.     END;
  1916.     editChanged := TRUE;
  1917.     ShowFileChanged(ed);
  1918.     IF el > 0
  1919.     THEN
  1920.       DEALLOCATE (editLine.text, 0);
  1921.       editLine.text := Zeile.text;
  1922.       editLine.length := Zeile.length;
  1923.     END;
  1924.     editLen := LENGTH (editLine.text^);
  1925.     v.bool := EditBase.PutCurrLine (ed);
  1926.     (* currRow hinter Wort setzen *)
  1927.     INC (currRow, tl);
  1928.     IF ~(silent IN findMode)
  1929.     THEN
  1930.       HideMouse();
  1931.       CenterCurrline (ed);
  1932.       ClearBlock (ed);
  1933.       drawLine (ed, SHORT(currLineNr - StartLine));
  1934.       ShowMouse(FALSE);
  1935.     END;
  1936.   END (* WITH ed *);
  1937. END ReplaceWord;
  1938.  
  1939. PROCEDURE EndSearch ();
  1940. (* Gibt das compilierte Suchmuster wieder frei
  1941.  *)
  1942.   VAR i : INTEGER;
  1943. BEGIN
  1944.   IF searchInited THEN
  1945.     Find2.Dispose (pPatt);
  1946.     searchInited := FALSE;
  1947.     FOR i := 0 TO 9 DO
  1948.       oneWildNumbers[i] := 0;
  1949.       allWildNumbers[i] := 0;
  1950.     END;
  1951.   END;
  1952. END EndSearch;
  1953.  
  1954. BEGIN
  1955.   searchInited := FALSE;
  1956.   undoList := NIL;
  1957.   NEW (saveLinePtr);
  1958.   IF saveLinePtr = NIL THEN HALT END;
  1959.   saveLinePtr^.zeile.length := 0;
  1960.   saveLinePtr^.zeile.text   := NIL;
  1961.   saveLineNr := -1;
  1962.   system := 0;
  1963.   undoBuffer.whatToUndo := nothingToDo;
  1964.   undoBuffer.buffer := NIL;
  1965. END EditTools.
  1966.